#pragma once

#include "Common.hpp"
#include "Log.hpp"
#include "InetAddr.hpp"
#include "ThreadPool.hpp"

using namespace LogModule;
using namespace ThreadPoolModule;

using task_t = std::function<void()>;                   // 任务类型, void() -> task_t
using func_t = std::function<std::string(const std::string&, InetAddr&)>; // 回调函数类型, 翻译函数

const int defaultsockfd = -1; // 默认全局socket文件描述符
const int defaultbacklog = 8; // 默认listen队列长度

class TcpServer : public NonCopy
{
public:
    // 构造函数
    TcpServer(uint16_t port, func_t func)
        : _port(port),
          _litsensockfd(defaultsockfd),
          _isrunning(false),
          _func(func)
    {
    }

    // server初始化函数
    void Init()
    {
        // 1. 创建socket
        _litsensockfd = socket(AF_INET, SOCK_STREAM, 0); // TCP socket
        if (_litsensockfd == -1)
        {
            LOG(LogLevel::FATAL) << "socket error, 创建套接字失败!";
            exit(SOCKET_ERR);
        }
        LOG(LogLevel::INFO) << "socket success, 创建套接字成功! sockfd: " << _litsensockfd;

        // 2. 绑定地址
        // 设置地址结构体
        InetAddr local(_port); // 构造InetAddr对象, 采用只传入port构造方法

        int n = bind(_litsensockfd, local.NetAddrPtr(), local.NetAddrLen()); // 绑定地址
        if (n < 0)
        {
            // 绑定失败
            LOG(LogLevel::FATAL) << "bind error, socket绑定地址失败!";
            exit(BIND_ERR);
        }
        // 绑定成功
        LOG(LogLevel::INFO) << "bind success, socket绑定地址成功!";

        // 3. 设置listen状态
        int nlisten = listen(_litsensockfd, defaultbacklog); // 监听
        if (nlisten < 0)
        {
            // 监听失败
            LOG(LogLevel::FATAL) << "listen error, socket监听失败!";
            exit(LISTEN_ERR);
        }
        // 监听成功
        LOG(LogLevel::INFO) << "listen success, socket监听成功!";
    }

    // 服务函数
    void Service(int sockfd, InetAddr &peer)
    {
        char buffer[1024]; // 初始化接收缓冲区
        while (1)
        {
            int n = read(sockfd, buffer, sizeof(buffer)); // 读取客户端socket文件数据
            if (n > 0)
            {
                // 读取client成功, buffer为待翻译的单词
                buffer[n] = '\0'; // 字符串结尾
                LOG(LogLevel::DEBUG) << "recv from " << peer.StringAddr() << ", say word: " << buffer;

                std::string echostring = _func(buffer, peer);// 调用回调函数, 翻译单词

                // server返回
                std::string echo_string = "Server echo# ";
                echo_string += echostring;

                write(sockfd, echo_string.c_str(), echo_string.size()); // 向client发送数据
            }
            else if (n == 0)
            {
                // 客户端断开连接
                LOG(LogLevel::DEBUG) << "client: " << peer.StringAddr() << " 退出连接!";
                close(sockfd); // 关闭socket连接
                break;
            }
            else
            {
                // 读取失败
                LOG(LogLevel::DEBUG) << "client: " << peer.StringAddr() << " 读取异常!";
                close(sockfd); // 关闭socket连接
                break;
            }
        }
    }

    // 线程参数结构体
    class ThreadData
    {
    public:
        // 构造函数
        ThreadData(int fd, InetAddr &ar, TcpServer *s) : sockfd(fd), addr(ar), tsvr(s)
        {
        }

    public:
        int sockfd;      // 客户端socket文件描述符
        InetAddr addr;   // 客户端地址
        TcpServer *tsvr; // server对象指针
    };

    // 线程函数Routine
    static void *Routine(void *arg)
    {
        pthread_detach(pthread_self()); // 线程分离

        ThreadData *data = static_cast<ThreadData *>(arg); // 强制类型转换
        data->tsvr->Service(data->sockfd, data->addr);     // 服务客户端请求

        delete data; // 释放线程参数结构体
        return nullptr;
    }

    // server启动函数
    void Run()
    {
        _isrunning = true;
        while (1)
        {
            // 1. 等待客户端连接
            struct sockaddr_in peer;      // 客户端地址结构体, 初始化
            socklen_t len = sizeof(peer); // 获取地址结构体长度

            int sockfd = accept(_litsensockfd, CONV(peer), &len); // 接收客户端连接
            if (sockfd < 0)
            {
                // 接收失败
                LOG(LogLevel::WARNING) << "accept error, 接受一客户端连接失败!";
                continue;
            }
            // 接收成功
            InetAddr addr(peer); // 构造InetAddr对象, 采用传入peer结构体构造方法
            LOG(LogLevel::INFO) << "accept success, 接受一客户端连接成功! peer addr: " << addr.StringAddr();

            // 2.3 多线程版本
            // 创建线程所需参数结构体
            ThreadData *data = new ThreadData(sockfd, addr, this);

            // 创建线程
            pthread_t tid;
            pthread_create(&tid, nullptr, Routine, data);

            // 2. 服务客户端请求
            // 2.1 单进程版本 Service(sockfd, addr);

            // 2.2 多进程版本
            /* pid_t pid = fork(); // 创建子进程
            if (pid < 0)
            {
                // 创建子进程失败
                LOG(LogLevel::FATAL) << "fork error, 创建子进程失败!";
                exit(FORK_ERR);
            }
            else if (pid == 0)
            {
                // 子进程, 负责服务客户端请求
                close(_litsensockfd); // 关闭父进程的socket文件描述符

                if(fork() > 0)
                {
                    exit(OK); // 子进程退出
                }

                Service(sockfd, addr); // 孙子进程服务客户端请求
                exit(OK); // 子进程退出
            }
            else
            {
                // 父进程, 负责socket连接
                close(sockfd); // 关闭子进程的socket文件描述符

                int ret = waitpid(pid, nullptr, 0); // 等待子进程退出
            } */

            /* // 2.4 线程池版本
            // 创建线程池
            ThreadPool<task_t>::GetInstance()->Enqueue([this, sockfd, &addr]()
                                                       { this->Service(sockfd, addr); }); */
        }

        _isrunning = false;
    }

    // 析构函数
    ~TcpServer()
    {
    }

private:
    int _litsensockfd; // server socket文件描述符
    uint16_t _port;    // server端口号

    bool _isrunning; // server是否正在运行

    func_t _func; // 回调函数
};